#!/bin/bash -eu
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

if [ ! -d "logs" ]; then
  # Create logs dir if it does not exist
  mkdir -p logs
else
  # Wipe it clean if it does exist
  rm -rf logs/*
fi

# Wipe the out directory if it exists
rm -rf out/*

# Print DUT version hash to log
echo | tee logs/exp.log
echo "Fuzzing Stats:" | tee logs/exp.log
echo "    DUT: $TOPLEVEL" | tee logs/exp.log
if [ -v DUT_HDL_DIR ]; then
  pushd $DUT_HDL_DIR >/dev/nul
  echo "    Version: $(git rev-parse HEAD)" | tee $DUT/logs/exp.log
  popd >/dev/null
else
  echo "    Version: n/a" | tee $DUT/logs/exp.log
fi
echo "    Start Time: $(date +%s)" | tee logs/exp.log
echo | tee logs/exp.log

# Generate HDL (if necessary)
command -v generate-hdl >/dev/null 2>&1 &&
  {
    generate-hdl 2>&1 | tee logs/exp.log
  }

if [[ $FUZZER == "sim" ]]; then
  if [[ $TB_TYPE == "cocotb" ]]; then

    # Simulate the DUT with cocotb testbench
    cocotb-verilator-sim 2>&1 | tee -a logs/exp.log

  elif [[ $TB_TYPE == "cpp" ]]; then

    # Simulate the DUT using C++ testbench
    cpp-verilator-sim 2>&1 | tee -a logs/exp.log

  else
    echo "ERROR: unsupported testbench type. Aborting!" | tee -a logs/exp.log
  fi

  # Save simulation results to GCS
  save-fuzzing-data

elif [[ $FUZZER == "afl" || $FUZZER == "afl-term-on-crash" ]]; then
  if [[ $TB_TYPE == "cocotb" ]]; then
    # cocotb Required Environment Vars.
    export MODULE=tb.$TB_TYPE.$TB.${TOPLEVEL}_tb
    export TOPLEVEL_LANG=verilog
  fi

  # Compile the DUT for fuzzing
  compile 2>&1 | tee -a logs/exp.log

  # Fuzz the DUT
  #time BIN_DIR=bin fuzz 2> | tee -a logs/exp.log
  ( time BIN_DIR=bin fuzz ) 2> logs/fuzz_time.log

  # Save fuzzing results to GCS
  if [[ $RUN_ON_GCP == "1" ]]; then
    save-fuzzing-data
  fi

  # Trace coverage of fuzzer-generated inputs with kcov, and Verilator
  if ! run-kcov 2>&1 | tee -a logs/exp.log; then
    echo "WARNING: run-kcov did not finish... probably ran out of resources." |
      tee -a logs/exp.log
  else
    # Extract kcov results into a plotting-friendly CSV file
    # TODO(ttrippel): make this script fuzzer-agnostic
    python3 $HW/hwfutils/hwfutils/extract_kcov.py $TOPLEVEL logs/kcov
  fi
  if ! run-vlt-cov 2>&1 | tee -a logs/exp.log; then
    echo "WARNING: run-vlt-cov did not finish... probably ran out of resources." |
      tee -a logs/exp.log
  fi
  if ! run-llvm-cov 2>&1 | tee -a logs/exp.log; then
    echo "WARNING: run-llvm-cov did not finish... probably ran out of resources." |
      tee -a logs/exp.log
  else
    # Extract kcov results into a plotting-friendly CSV file
    # TODO(ttrippel): make this script fuzzer-agnostic
    python3 $HW/hwfutils/hwfutils/extract_llvm_cov.py $TOPLEVEL logs/llvm-cov
  fi

  # Save coverage tracing data
  if [[ $RUN_ON_GCP == "1" ]]; then
    save-coverage-data
  fi

else
  echo "ERROR: unsupported fuzzer. Aborting!" | tee -a logs/exp.log
fi

# If simulating/fuzzing on GCP, save data and tear down VM
if [[ $RUN_ON_GCP == "1" ]]; then
  gcp-shutdown-vm
fi
exit 0
